﻿using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Globalization;

namespace MNS.Activities.Common
{
    [TypeConverter(typeof(TimeTypeConverter))]
    public class Time
    {
        protected bool _IsSet = false;
        [DefaultValue(false)]
        public bool IsSet
        {
            get { return _IsSet; }
            set
            {
                if (_IsSet && (!value))
                {
                    _Hours = 0;
                    _Minutes = 0;
                    _Seconds = 0;
                    _MilliSeconds = 0;
                }

                _IsSet = value;
            }
        }

        protected int _Hours = 0;
        [DefaultValue(0)]
        public int Hours
        {
            get { return _Hours; }
            set
            {
                _Hours = value % 24;
            }
        }

        protected int _Minutes = 0;
        [DefaultValue(0)]
        public int Minutes
        {
            get { return _Minutes; }
            set
            {
                _Minutes = value % 60;
                Hours += (int)(value / 60);
            }
        }

        protected int _Seconds = 0;
        [DefaultValue(0)]
        public int Seconds
        {
            get { return _Seconds; }
            set
            {
                _Seconds = value % 60;
                Minutes += (int)(value / 60);
            }
        }

        protected int _MilliSeconds = 0;
        [DefaultValue(0)]
        public int MilliSeconds
        {
            get { return _MilliSeconds; }
            set
            {
                _MilliSeconds = value % 1000;
                Seconds += (int)(value / 1000);
            }
        }

        public static Time Default
        {
            get
            {
                return new Time()
                    {
                        IsSet = false,
                        Hours = 0,
                        Minutes = 0,
                        Seconds = 0,
                        MilliSeconds = 0
                    };
            }
        }
    }

    internal class TimeTypeConverter : TypeConverter
    {
        public override PropertyDescriptorCollection GetProperties(
            ITypeDescriptorContext context,
            object value,
            Attribute[] filter)
        {
            return TypeDescriptor.GetProperties(value, filter);
        }

        public override bool GetPropertiesSupported(ITypeDescriptorContext context)
        {
            return true;
        }

        public override bool CanConvertFrom(
         ITypeDescriptorContext context, Type t)
        {

            if (t == typeof(string))
            {
                return true;
            }
            return base.CanConvertFrom(context, t);
        }

        public override object ConvertFrom(
              ITypeDescriptorContext context,
              CultureInfo info,
               object value)
        {
            Time result = null;
            if (value != null && value is string)
            {
                try
                {
                    string s = (string) value;

                    if (s.Trim() == "---")
                        return new Time()
                            {
                                IsSet = false,
                                Hours = 0,
                                Minutes = 0,
                                Seconds = 0,
                                MilliSeconds = 0
                            };
                    
                    // parse the format "hh:mm:ss msms"
                    s = s.Trim();
                    if(s.Length >= 1)
                    {
                        int hours = 0;
                        int minutes = 0;
                        int seconds = 0;
                        int milliseconds = 0;

                        result = new Time();
                    
                    
                        string[] parts = s.Split(' ');
                        if (parts.Length >= 2)
                            if (!int.TryParse(parts[1], out milliseconds))
                                milliseconds = -1;

                        parts = parts[0].Split(':');
                        if (parts.Length >= 3)
                            if (!int.TryParse(parts[2], out seconds))
                                seconds = -1;

                        if (parts.Length >= 2)
                            if (!int.TryParse(parts[1], out minutes))
                                minutes = -1;

                        if (parts.Length >= 1)
                            if (!int.TryParse(parts[0], out hours))
                                hours = -1;

                        if (milliseconds < 0
                            || seconds < 0
                            || milliseconds < 0
                            || hours < 0)
                            result = null;
                    }
                }
                catch
                {
                    result = null;
                }

                if (result == null)
                  throw new ArgumentException( "Can not convert '" + (string)value + "' to type Person");

                return result;
            }

            return base.ConvertFrom(context, info, value);
        }

        public override object ConvertTo(
                 ITypeDescriptorContext context,
                 CultureInfo culture,
                 object value,
                 Type destType)
        {
            if (value == null)
                return "---";
            if (destType == typeof(string) && value is Time)
            {
                Time t = (Time)value;
                
                if(!t.IsSet)
                    return "---";

                return t.Hours.ToString().PadLeft(2, '0') + ":"
                    + t.Minutes.ToString().PadLeft(2, '0') + ":"
                    + t.Seconds.ToString().PadLeft(2, '0') + " "
                    + t.MilliSeconds.ToString().PadLeft(3, '0');
            }
            return base.ConvertTo(context, culture, value, destType);
        }
    }
}
